#pragma once

#include "util.hpp"

#include <jsoncpp/json/json.h>

#define CRLF "\r\n"
#define CRLF_LEN strlen(CRLF)
#define SPACE " "
#define SPACE_LEN strlen(SPACE)

#define OPS "+-*/%"

// #define MY_SELF 1

std::string decode(std::string &in, uint32_t *len)
{
    assert(len);
    // 1.确认是否是一个包含len的有效字符串
    *len = 0;
    std::size_t pos = in.find(CRLF);
    if(pos == std::string::npos) return "";
    // 2.提取长度
    std::string inLen = in.substr(0, pos);
    int intLen = atoi(inLen.c_str());
    // 3.确认有效载荷是否符合要求
    int surplus = in.size() - 2 * CRLF_LEN - pos;
    if(surplus < intLen) return "";
    // 4.确认有完整的报文结构
    std::string package = in.substr(pos + CRLF_LEN, intLen);
    *len = intLen;
    // 5.将当前报文完整的从in中全部移除掉
    int removeLen = inLen.size() + package.size() + 2 * CRLF_LEN;
    in.erase(0, removeLen);
    // 6.正常返回
    return package;
}

std::string encode(const std::string &in, uint32_t len)
{
    std::string encodein = std::to_string(len);
    encodein += CRLF;
    encodein += in;
    encodein += CRLF;

    return encodein;
}

class Request
{
public:
    Request()
    {}

    ~Request()
    {}

    // 序列化
    void serialize(std::string *out)
    {
#ifdef MY_SELF
        std::string xstr = std::to_string(x_);
        std::string ystr = std::to_string(y_);

        *out = xstr;
        *out += SPACE;
        *out += op_;
        *out += SPACE;
        *out += ystr;
#else
        //json
        // 1. Value对象，万能对象
        // 2. json是基于KV
        // 3. json有两套操作方法
        // 4. 序列化的时候，会将所有的数据内容，转换成为字符串
        Json::Value root;
        root["x"] = x_;
        root["y"] = y_;
        root["op"] = op_;

        Json::FastWriter fw;
        *out = fw.write(root);
#endif
    }

    // 反序列化
    bool deserialize(std::string &in)
    {
#ifdef MY_SELF
        std::size_t spaceOne = in.find(SPACE);
        if(std::string::npos == spaceOne) return false;
        std::size_t spaceTwo = in.rfind(SPACE);
        if(std::string::npos == spaceTwo) return false;

        std::string dataOne = in.substr(0, spaceOne);
        std::string dataTwo = in.substr(spaceTwo + SPACE_LEN);
        std::string oper = in.substr(spaceOne + SPACE_LEN, spaceTwo - (spaceOne + SPACE_LEN));
        if(oper.size() != 1) return false;

        x_ = atoi(dataOne.c_str());
        y_ = atoi(dataTwo.c_str());
        op_ = oper[0];

        return true;
#else
        Json::Value root;
        Json::Reader rd;
        rd.parse(in, root);
        x_ = root["x"].asInt();
        y_ = root["y"].asInt();
        op_ = root["op"].asInt();

        return true;
#endif
    }

    void debug()
    {
        std::cout << "#################################" << std::endl;
        std::cout << "x_: " << x_ << std::endl;
        std::cout << "op_: " << op_ << std::endl;
        std::cout << "y_: " << y_ << std::endl;
        std::cout << "#################################" << std::endl;
    }
public:
    int x_;
    int y_;
    char op_;
};

class Response
{
public:
    Response() : exitCode_(0), result_(0)
    {}

    ~Response()
    {}

    void serialize(std::string *out)
    {
#ifdef MY_SELF
        std::string ec = std::to_string(exitCode_);
        std::string res = std::to_string(result_);

        *out = ec;
        *out += SPACE;
        *out += res;
#else
        Json::Value root;
        root["exitcode"] = exitCode_;
        root["result"] = result_;

        Json::FastWriter fw;
        *out = fw.write(root);
#endif
    }

    bool deserialize(std::string &in)
    {
#ifdef MY_SELF
        std::size_t pos = in.find(SPACE);
        if(std::string::npos == pos) return false;
        std::string codestr = in.substr(0, pos);
        std::string reststr = in.substr(pos + SPACE_LEN);

        exitCode_ = atoi(codestr.c_str());
        result_ = atoi(reststr.c_str());
        return true;
#else
        Json::Value root;
        Json::Reader rd;
        rd.parse(in, root);
        exitCode_ = root["exitcode"].asInt();
        result_ = root["result"].asInt();

        return true;
#endif
    }

    void debug()
    {
        std::cout << "#################################" << std::endl;
        std::cout << "exitCode_: " << exitCode_ << std::endl;
        std::cout << "result_: " << result_ << std::endl;
        std::cout << "#################################" << std::endl;
    }
public:
    int exitCode_;
    int result_;
};

bool makeReuquest(const std::string &str, Request *req)
{
    char strtmp[BUFFER_SIZE];
    snprintf(strtmp, sizeof strtmp, "%s", str.c_str());
    char *left = strtok(strtmp, OPS);
    if(!left) return false;
    char *right = strtok(nullptr, OPS);
    if(!right) return false;
    char mid = str[strlen(left)];

    req->x_ = atoi(left);
    req->y_ = atoi(right);
    req->op_ = mid;

    return true;
}